boxlayout: Compute opposite size properly
authorBenjamin Otte <otte@redhat.com>
Fri, 5 Nov 2021 19:30:49 +0000 (20:30 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 5 Nov 2021 19:30:49 +0000 (20:30 +0100)
For size -1 in the opposite orientation, GtkBoxLayout used to measure
the children based on their min size in the box's orientation instead of
-1. That wasn't really intended, but was a side effect of how the sizing
code did (not) distribute extra size above the minimum size.

This is clearly not what we want.
What we want is measuring the orientation as is for size -1. Then we
want to just take the maximum of all children and use that.

A reftest is incldued that ensures a vbox wraps a label just like an
hbox does.

gtk/gtkboxlayout.c
testsuite/reftests/meson.build
testsuite/reftests/vbox-with-max-width-chars-label.ref.ui [new file with mode: 0644]
testsuite/reftests/vbox-with-max-width-chars-label.ui [new file with mode: 0644]

index f0807488307db35b218e6a4993e41d240b00d49b..99feca37e51172275a748749d5bf689256d83ebb 100644 (file)
@@ -256,11 +256,46 @@ gtk_box_layout_compute_size (GtkBoxLayout *self,
 static void
 gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
                                       GtkWidget    *widget,
-                                      int           for_size,
                                       int          *minimum,
                                       int          *natural,
                                       int          *min_baseline,
                                       int          *nat_baseline)
+{
+  GtkWidget *child;
+  int largest_min = 0, largest_nat = 0;
+
+  for (child = gtk_widget_get_first_child (widget);
+       child != NULL;
+       child = gtk_widget_get_next_sibling (child))
+    {
+      int child_min = 0;
+      int child_nat = 0;
+
+      if (!gtk_widget_should_layout (child))
+        continue;
+
+      gtk_widget_measure (child,
+                          OPPOSITE_ORIENTATION (self->orientation),
+                          -1,
+                          &child_min, &child_nat,
+                          NULL, NULL);
+
+      largest_min = MAX (largest_min, child_min);
+      largest_nat = MAX (largest_nat, child_nat);
+    }
+
+  *minimum = largest_min;
+  *natural = largest_nat;
+}
+
+static void
+gtk_box_layout_compute_opposite_size_for_size (GtkBoxLayout *self,
+                                               GtkWidget    *widget,
+                                               int           for_size,
+                                               int          *minimum,
+                                               int          *natural,
+                                               int          *min_baseline,
+                                               int          *nat_baseline)
 {
   GtkWidget *child;
   int nvis_children;
@@ -437,9 +472,18 @@ gtk_box_layout_measure (GtkLayoutManager *layout_manager,
 
   if (self->orientation != orientation)
     {
-      gtk_box_layout_compute_opposite_size (self, widget, for_size,
-                                            minimum, natural,
-                                            min_baseline, nat_baseline);
+      if (for_size < 0)
+        {
+          gtk_box_layout_compute_opposite_size (self, widget,
+                                                minimum, natural,
+                                                min_baseline, nat_baseline);
+        }
+      else
+        {
+          gtk_box_layout_compute_opposite_size_for_size (self, widget, for_size,
+                                                         minimum, natural,
+                                                         min_baseline, nat_baseline);
+        }
     }
   else
     {
index b033760ed7fab6ebab05ded69bbd0ddba11f44e0..692a4274385772aae50e29f4aef50a517b26d8dd 100644 (file)
@@ -498,6 +498,8 @@ testdata = [
   'unresolvable.css',
   'unresolvable.ref.ui',
   'unresolvable.ui',
+  'vbox-with-max-width-chars-label.ref.ui',
+  'vbox-with-max-width-chars-label.ui',
   'window-border-width.ref.ui',
   'window-border-width.ui',
   'window-default-size.ref.ui',
diff --git a/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui b/testsuite/reftests/vbox-with-max-width-chars-label.ref.ui
new file mode 100644 (file)
index 0000000..aa732c6
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkWindow">
+    <property name="decorated">0</property>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">horizontal</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="label">Hello World</property>
+            <property name="wrap">1</property>
+            <property name="max-width-chars">1</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/testsuite/reftests/vbox-with-max-width-chars-label.ui b/testsuite/reftests/vbox-with-max-width-chars-label.ui
new file mode 100644 (file)
index 0000000..3a7d52e
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkWindow">
+    <property name="decorated">0</property>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="label">Hello World</property>
+            <property name="wrap">1</property>
+            <property name="max-width-chars">1</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>